using System;
using System.ComponentModel;
using System.Linq.Expressions;
using Microsoft.Phone.Shell;

namespace FluentAppBar
{
    internal class SetupButtonContainer<T, TButton> : IDisposable
        where T : INotifyPropertyChanged
        where TButton : class, IApplicationBarMenuItem
    {
        private readonly T _viewModel;
        private readonly Action<TButton, T> _onClick;
        private readonly string _propertyName;
        private readonly Action<TButton, T> _isEnabledChanged;
        private readonly TButton _button;
        private readonly Func<T, bool> _getEnabled;

        public SetupButtonContainer(
            TButton button, 
            T viewModel,
            Action<TButton, T> onClick,
            Expression<Func<T, bool>> isEnabledProperty = null,
            Action<TButton, T> isEnabledChanged = null)
        {
            _button = button;
            _viewModel = viewModel;
            _onClick = onClick;
            _isEnabledChanged = isEnabledChanged;


            if (isEnabledProperty != null)
            {
                _propertyName = isEnabledProperty.GetName();
                _getEnabled = isEnabledProperty.Compile();
                ChangeButtonState();

                _viewModel.PropertyChanged += ViewModelOnPropertyChanged;
            }

            button.Click += ButtonOnClick;
        }

        private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            if (propertyChangedEventArgs.PropertyName != _propertyName)
                return;

            ChangeButtonState();
        }

        private void ButtonOnClick(object sender, EventArgs eventArgs)
        {
            _onClick(_button, _viewModel);
        }

        private void ChangeButtonState()
        {
            bool newValue = _getEnabled(_viewModel);

            if (_isEnabledChanged == null)
            {
                _button.IsEnabled = newValue;
            }
            else
            {
                _isEnabledChanged(_button, _viewModel);
            }
        }

        public void Dispose()
        {
            _button.Click -= ButtonOnClick;
            _viewModel.PropertyChanged -= ViewModelOnPropertyChanged;
        }
    }
}